{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [Dictionaries](https://docs.python.org/3/library/stdtypes.html#dict) \n",
    "Collections of `key`-`value` pairs. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_empty_dict = {}  # alternative: my_empty_dict = dict()\n",
    "print('dict: {}, type: {}'.format(my_empty_dict, type(my_empty_dict)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dict1 = {'value1': 1.6, 'value2': 10, 'name': 'John Doe'}\n",
    "dict2 = dict(value1=1.6, value2=10, name='John Doe')\n",
    "\n",
    "print(dict1)\n",
    "print(dict2)\n",
    "\n",
    "print('equal: {}'.format(dict1 == dict2))\n",
    "print('length: {}'.format(len(dict1)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `dict.keys(), dict.values(), dict.items()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('keys: {}'.format(dict1.keys()))\n",
    "print('values: {}'.format(dict1.values()))\n",
    "print('items: {}'.format(dict1.items()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Accessing and setting values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict = {}\n",
    "my_dict['key1'] = 'value1'\n",
    "my_dict['key2'] = 99\n",
    "my_dict['key1'] = 'new value'  # overriding existing value\n",
    "print(my_dict)\n",
    "print('value of key1: {}'.format(my_dict['key1']))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Accessing a nonexistent key will raise `KeyError` (see [`dict.get()`](#dict_get) for workaround):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# print(my_dict['nope'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Deleting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict = {'key1': 'value1', 'key2': 99, 'keyX': 'valueX'}\n",
    "del my_dict['keyX']\n",
    "print(my_dict)\n",
    "\n",
    "# Usually better to make sure that the key exists (see also pop() and popitem())\n",
    "key_to_delete = 'my_key'\n",
    "if key_to_delete in my_dict:\n",
    "    del my_dict[key_to_delete]\n",
    "else:\n",
    "    print('{key} is not in {dictionary}'.format(key=key_to_delete, dictionary=my_dict))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dictionaries are mutable"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict = {'ham': 'good', 'carrot': 'semi good'}\n",
    "my_other_dict = my_dict\n",
    "my_other_dict['carrot'] = 'super tasty'\n",
    "my_other_dict['sausage'] = 'best ever'\n",
    "print('my_dict: {}\\nother: {}'.format(my_dict, my_other_dict))\n",
    "print('equal: {}'.format(my_dict == my_other_dict))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create a new `dict` if you want to have a copy:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict = {'ham': 'good', 'carrot': 'semi good'}\n",
    "my_other_dict = dict(my_dict)\n",
    "my_other_dict['beer'] = 'decent'\n",
    "print('my_dict: {}\\nother: {}'.format(my_dict, my_other_dict))\n",
    "print('equal: {}'.format(my_dict == my_other_dict))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='dict_get'></a>\n",
    "## `dict.get()`\n",
    "Returns `None` if `key` is not in `dict`. However, you can also specify `default` return value which will be returned if `key` is not present in the `dict`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict = {'a': 1, 'b': 2, 'c': 3}\n",
    "d = my_dict.get('d')\n",
    "print('d: {}'.format(d))\n",
    "\n",
    "d = my_dict.get('d', 'my default value')\n",
    "print('d: {}'.format(d))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `dict.pop()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict = dict(food='ham', drink='beer', sport='football')\n",
    "print('dict before pops: {}'.format(my_dict))\n",
    "\n",
    "food = my_dict.pop('food')\n",
    "print('food: {}'.format(food))\n",
    "print('dict after popping food: {}'.format(my_dict))\n",
    "\n",
    "food_again = my_dict.pop('food', 'default value for food')\n",
    "print('food again: {}'.format(food_again))\n",
    "print('dict after popping food again: {}'.format(my_dict))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `dict.setdefault()`\n",
    "Returns the `value` of `key` defined as first parameter. If the `key` is not present in the dict, adds `key` with default value (second parameter)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_dict = {'a': 1, 'b': 2, 'c': 3}\n",
    "a = my_dict.setdefault('a', 'my default value')\n",
    "d = my_dict.setdefault('d', 'my default value')\n",
    "print('a: {}\\nd: {}\\nmy_dict: {}'.format(a, d, my_dict))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `dict.update()`\n",
    "Merge two `dict`s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dict1 = {'a': 1, 'b': 2}\n",
    "dict2 = {'c': 3}\n",
    "dict1.update(dict2)\n",
    "print(dict1)\n",
    "\n",
    "# If they have same keys:\n",
    "dict1.update({'c': 4})\n",
    "print(dict1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The keys of a `dict` have to be immutable"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Thus you can not use e.g. a `list` or a `dict` as key because they are mutable types\n",
    ":"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# bad_dict = {['my_list'], 'value'}  # Raises TypeError"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Values can be mutable"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "good_dict = {'my key': ['Python', 'is', 'still', 'cool']}\n",
    "print(good_dict)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
